#pragma once

#include "Containers/Vector.h"
#include <inttypes.h>
#include <vulkan/vulkan.hpp>



//各种描述符的数量
struct SVulkanDescriptorNums
{
    int32_t CombinedImageSamplerDescriptorNum=0;
    int32_t UniformBufferDescriptorNum=0;
    int32_t InputAttachmentDescriptorNum=0;

    bool IsEmpty()const
    {
        return CombinedImageSamplerDescriptorNum==0
            && UniformBufferDescriptorNum==0
            && InputAttachmentDescriptorNum==0;
    }

    void Clear()
    {
        CombinedImageSamplerDescriptorNum=0;
        UniformBufferDescriptorNum=0;
        InputAttachmentDescriptorNum=0;
    }

    bool operator==(const SVulkanDescriptorNums& Other)const
    {
        return CombinedImageSamplerDescriptorNum==Other.CombinedImageSamplerDescriptorNum
            && UniformBufferDescriptorNum==Other.UniformBufferDescriptorNum
            && InputAttachmentDescriptorNum==Other.InputAttachmentDescriptorNum;
    }

    SVulkanDescriptorNums& operator+=(const SVulkanDescriptorNums& Other)
    {
        CombinedImageSamplerDescriptorNum+=Other.CombinedImageSamplerDescriptorNum;
        UniformBufferDescriptorNum+=Other.UniformBufferDescriptorNum;
        InputAttachmentDescriptorNum+=Other.InputAttachmentDescriptorNum;
        return *this;
    }

    SVulkanDescriptorNums operator+(const SVulkanDescriptorNums& Other)const
    {
        SVulkanDescriptorNums Result;
        Result.CombinedImageSamplerDescriptorNum=CombinedImageSamplerDescriptorNum+Other.CombinedImageSamplerDescriptorNum;
        Result.UniformBufferDescriptorNum=UniformBufferDescriptorNum+Other.UniformBufferDescriptorNum;
        Result.InputAttachmentDescriptorNum=InputAttachmentDescriptorNum+Other.InputAttachmentDescriptorNum;
        return Result;
    }

    SVulkanDescriptorNums operator*(int32_t Num)const
    {
        SVulkanDescriptorNums Result;
        Result.CombinedImageSamplerDescriptorNum=CombinedImageSamplerDescriptorNum*Num;
        Result.UniformBufferDescriptorNum=UniformBufferDescriptorNum*Num;
        Result.InputAttachmentDescriptorNum=InputAttachmentDescriptorNum*Num;
        return Result;
    }


    TVector<vk::DescriptorPoolSize> ToVkDescriptorPoolSize()const
    {
        TVector<vk::DescriptorPoolSize> Result;
        if(CombinedImageSamplerDescriptorNum>0)
        {
            vk::DescriptorPoolSize DescriptorPoolSize;
            DescriptorPoolSize.type=vk::DescriptorType::eCombinedImageSampler;
            DescriptorPoolSize.descriptorCount=CombinedImageSamplerDescriptorNum;
            Result.Add(DescriptorPoolSize);
        }
        if(UniformBufferDescriptorNum>0)
        {
            vk::DescriptorPoolSize DescriptorPoolSize;
            DescriptorPoolSize.type=vk::DescriptorType::eUniformBuffer;
            DescriptorPoolSize.descriptorCount=UniformBufferDescriptorNum;
            Result.Add(DescriptorPoolSize);
        }
        if(InputAttachmentDescriptorNum>0)
        {
            vk::DescriptorPoolSize DescriptorPoolSize;
            DescriptorPoolSize.type=vk::DescriptorType::eInputAttachment;
            DescriptorPoolSize.descriptorCount=InputAttachmentDescriptorNum;
            Result.Add(DescriptorPoolSize);
        }
        return Result;
    }

};

struct SVulkanDescriptorPoolSize
{
    //有多少个描述符集
    int32_t SetNum=0;

    //各种描述符的数量
    SVulkanDescriptorNums DescriptorNums;

    bool IsEmpty() const
    {
        return DescriptorNums.IsEmpty() && SetNum==0;
    }

    void Clear()
    {
        DescriptorNums.Clear();
        SetNum=0;
    }

    bool operator==(const SVulkanDescriptorPoolSize& Other)const
    {
        return DescriptorNums==Other.DescriptorNums && SetNum==Other.SetNum;
    }

    SVulkanDescriptorPoolSize& operator+=(const SVulkanDescriptorNums& Other)
    {
        DescriptorNums+=Other;
        return *this;
    }

    SVulkanDescriptorPoolSize operator+=(const SVulkanDescriptorPoolSize& Other)
    {
        DescriptorNums+=Other.DescriptorNums;
        SetNum+=Other.SetNum;
        return *this;
    }

    vk::DescriptorPool CreateDescriptorPool(vk::Device Device)const
    {
        if(SetNum==0)
        {
            return vk::DescriptorPool();
        }

        auto Sizes=DescriptorNums.ToVkDescriptorPoolSize();

        vk::DescriptorPoolCreateInfo DescriptorPoolInfo=vk::DescriptorPoolCreateInfo()
        .setMaxSets(SetNum)
        .setPoolSizes(Sizes);
        return Device.createDescriptorPool(DescriptorPoolInfo);
    }

};